﻿using System;
using System.IO;
using System.Collections.Generic;

namespace JetBlack.IO
{
    internal class NetworkReader : BinaryReader
    {
        public NetworkReader(Stream stream)
            : base(stream)
        {
        }

        public IDictionary<string, object> ReadDictionary()
        {
            int fieldCount = ReadInt32();

            if (fieldCount <= 0)
                return null;
            else
                return ReadDictionary(fieldCount);
        }

        private IDictionary<string, object> ReadDictionary(int count)
        {
            IDictionary<string, object> data = new Dictionary<string, object>(count);
            for (int i = 0; i < count; ++i)
                data.Add(ReadKeyValuePair());
            return data;
        }

        private KeyValuePair<string, object> ReadKeyValuePair()
        {
            string key = ReadString();
            TypeCode typeCode = (TypeCode)ReadByte();
            object value = ReadObject(typeCode);
            return new KeyValuePair<string, object>(key, value);
        }

        private object ReadObject(TypeCode typeCode)
        {
            switch (typeCode)
            {
                case TypeCode.Boolean:
                    return ReadBoolean();
                case TypeCode.Byte:
                    return ReadByte();
                case TypeCode.Char:
                    return ReadChar();
                case TypeCode.DateTime:
                    return new DateTime(ReadInt64());
                case TypeCode.DBNull:
                    return DBNull.Value;
                case TypeCode.Decimal:
                    return ReadDecimal();
                case TypeCode.Double:
                    return ReadDouble();
                case TypeCode.Empty:
                    return null;
                case TypeCode.Int16:
                    return ReadInt16();
                case TypeCode.Int32:
                    return ReadInt32();
                case TypeCode.Int64:
                    return ReadInt64();
                case TypeCode.SByte:
                    return ReadSByte();
                case TypeCode.Single:
                    return ReadSingle();
                case TypeCode.String:
                    return ReadString();
                case TypeCode.UInt16:
                    return ReadUInt16();
                case TypeCode.UInt32:
                    return ReadUInt32();
                case TypeCode.UInt64:
                    return (ulong)ReadInt64();
                case TypeCode.Object:
                default:
                    throw new InvalidDataException("unsupported field type");
            }
        }

        static private Type GetType(TypeCode typeCode)
        {
            switch (typeCode)
            {
                case TypeCode.Boolean:
                    return typeof(Boolean);
                case TypeCode.Byte:
                    return typeof(Byte);
                case TypeCode.Char:
                    return typeof(Char);
                case TypeCode.DateTime:
                    return typeof(DateTime);
                case TypeCode.DBNull:
                    return typeof(DBNull);
                case TypeCode.Decimal:
                    return typeof(Decimal);
                case TypeCode.Double:
                    return typeof(Double);
                case TypeCode.Empty:
                    return typeof(Object);
                case TypeCode.Int16:
                    return typeof(Int16);
                case TypeCode.Int32:
                    return typeof(Int32);
                case TypeCode.Int64:
                    return typeof(Int64);
                case TypeCode.Object:
                    return typeof(Object);
                case TypeCode.SByte:
                    return typeof(SByte);
                case TypeCode.Single:
                    return typeof(Single);
                case TypeCode.String:
                    return typeof(String);
                case TypeCode.UInt16:
                    return typeof(UInt16);
                case TypeCode.UInt32:
                    return typeof(UInt32);
                case TypeCode.UInt64:
                    return typeof(UInt64);
                default:
                    throw new InvalidDataException("unsupported field type code");
            }
        }
    }
}
